<template>
  <el-select
    ref="selectRef"
    v-model="selectedIds"
    v-bind="$attrs"
    :filter-method="selectFilterMethod"
    @visible-change="selectVisibleChangeHandler"
    @focus="focusHandler"
    @change="selectChangeHandler"
  >
    <el-option disabled class="tree-option" :value="null">
      <el-tree
        :data="treeData"
        class="tree"
        ref="treeRef"
        v-bind="treeOptions"
        :node-key="(treeOptions && treeOptions.nodeKey) || commonProps.id"
        :props="{
          id: commonProps.id,
          label: commonProps.name,
          children: commonProps.children,
        }"
        :filterNodeMethod="filterNodeMethod"
        :show-checkbox="multiple"
        default-expand-all
        :highlight-current="!multiple"
        :expand-on-click-node="multiple || leafOnly"
        @node-expand="nodeExpandHandler"
        @node-collapse="nodeCollapseHandler"
        @node-click="treeClickHandler"
        @check="treeCheckHandler"
      />
    </el-option>
    <!--  将其余的选型隐藏掉  -->
    <el-option
      v-for="item in plainData.filter(e => (multiple ? e.isLeaf : leafOnly ? e.isLeaf : true))"
      :key="item[commonProps.id]"
      :value="item[commonProps.id]"
      :label="item[commonProps.name]"
      v-show="false"
    />
  </el-select>
</template>
<script>
export default {
  name: 'TreeSelect',
  props: {
    value: {
      type: [Array, String, Number],
    },
    data: {
      type: Array,
      default: () => [],
    },
    leafOnly: Boolean,
    treeOptions: {
      type: Object,
      default: () => ({}),
    },
  },
  data: () => ({
    treeData: [],
    plainData: [],
    selectedIds: [],
    lastHighlightNodeId: undefined,
    panelScrollTop: 0,
  }),
  watch: {
    data: {
      handler() {
        this.treeData = this.data;
        this.plainData = this.getPlainTreeData(this.data);
        this.panelScrollTop = 0;
      },
      deep: true,
      immediate: true,
    },
    value: {
      handler() {
        if (this.multiple) {
          // 多选
          this.selectedIds = JSON.parse(JSON.stringify(this.value));
          this.$nextTick(() => {
            this.$refs.treeRef.setCheckedKeys(
              this.value.filter(id => this.plainData.find(item => item.id === id)?.isLeaf),
            );
          });
        } else {
          // 单选
          this.selectedIds = this.value;
          if (this.leafOnly && !this.plainData.find(e => e[this.commonProps.id] === this.value)?.isLeaf) {
            this.lastHighlightNodeId = undefined;
            this.$nextTick(() => {
              this.$refs.treeRef.setCurrentKey(undefined);
            });
          } else {
            this.lastHighlightNodeId = this.value || undefined;
            this.$nextTick(() => {
              this.$refs.treeRef.setCurrentKey(this.value || undefined);
            });
          }
        }
      },
      deep: true,
      immediate: true,
    },
  },
  computed: {
    commonProps() {
      return {
        id: this.$attrs?.props?.id || 'id',
        name: this.$attrs?.props?.name || 'name',
        children: this.$attrs?.props?.children || 'children',
      };
    },
    multiple() {
      return Object.keys(this.$attrs).includes('multiple') && this.$attrs.multiple !== false;
    },
  },
  methods: {
    getPlainTreeData(treeData, result = []) {
      // 初始化下拉菜单本身的选项
      treeData.forEach(e => {
        const current = {
          [this.commonProps.id]: e[this.commonProps.id],
          [this.commonProps.name]: e[this.commonProps.name],
        };
        result.push(current);
        if (e[this.commonProps.children]?.length) {
          this.getPlainTreeData(e[this.commonProps.children], result);
        } else {
          current.isLeaf = true;
        }
      });
      return result;
    },
    treeClickHandler(val, node) {
      // 树选中节点（单选时）
      if (!this.multiple) {
        if (this.leafOnly && !node.isLeaf) {
          this.$refs.treeRef.setCurrentKey(this.lastHighlightNodeId);
          return;
        }
        this.lastHighlightNodeId = val.id;

        this.selectedIds = val[this.commonProps.id];
        this.$refs.selectRef.handleClose();
        this.$emit('input', this.selectedIds);
      }
    },
    treeCheckHandler() {
      // 树选中节点（多选时）
      if (this.multiple) {
        this.selectedIds = this.$refs.treeRef.getCheckedKeys(true);
        this.$emit('input', [...this.selectedIds]);
      }
    },
    selectChangeHandler(values) {
      // 下拉选中内容改变时
      if (this.multiple) {
        this.$refs.treeRef.setCheckedKeys(values);
      } else {
        this.lastHighlightNodeId = values || undefined;
        this.$refs.treeRef.setCurrentKey(values || undefined);
      }
      this.$emit('input', values);
    },
    nodeCollapseHandler() {
      setTimeout(() => {
        this.$refs.selectRef.broadcast('ElSelectDropdown', 'updatePopper');
      }, 10);
    },
    nodeExpandHandler() {
      setTimeout(() => {
        this.$refs.selectRef.broadcast('ElSelectDropdown', 'updatePopper');
      }, 10);
    },
    // 筛选功能相关
    selectFilterMethod(val) {
      this.$refs.treeRef.filter(val);
    },
    filterNodeMethod(val, data) {
      if (!val) {
        return true;
      }
      return String(data.name).toLowerCase().includes(String(val).toLowerCase());
    },
    selectVisibleChangeHandler(isVisible) {
      if (!isVisible) {
        this.panelScrollTop = this.$refs.selectRef.$refs.scrollbar.$el.children[0].scrollTop;
      }
      setTimeout(() => {
        this.$refs.treeRef.filter();
      }, 100);
    },
    focusHandler() {
      setTimeout(() => {
        this.$refs.selectRef.$refs.scrollbar.$el.children[0].scrollTo({ top: this.panelScrollTop || 0 });
      });
    },
  },
};
</script>

<style scoped>
.tree-option {
  width: 100%;
  line-height: 0;
  padding: 0 !important;
  height: 100%;
  overflow: auto;
}

.tree {
  font-weight: normal;
  width: 100%;
}

::v-deep .el-tree-node__content {
  padding-right: 10px;
}

::v-deep .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
  font-weight: bold;
}

::v-deep .el-tree-node__children {
  width: 0;
  overflow: hidden;
}

::v-deep .el-tree-node__children[aria-expanded='true'] {
  position: relative;
  width: 100%;
}

::v-deep .el-select-dropdown__list > * {
  display: none;
}

::v-deep .el-select-dropdown__list > *:first-child {
  display: block;
}
</style>
